//
//  ACMemoryStorage.m
//  ACCache_Example
//
//  Created by autohome on 2021/8/7.
//  Copyright © 2021 CaiXiang. All rights reserved.
//

#import "ACMemoryCache.h"
#import <UIKit/UIKit.h>
#import <pthread.h>
#import "ACNSCache.h"
#import "ACDoubleLinkedList.h"
#import "ACLinkedNode.h"
#import "ACLFUCache.h"

typedef NS_ENUM(NSUInteger,ACMStorageType) {
    ACMStorageTypeSystemCache = 0,
    ACMStorageTypeLFUCache = 1,
};

@interface ACMemoryCache() {
    ACNSCache *_cache;
    ACLFUCache *_lfuCache;
    ACMStorageType _storageType;
}

@end

@implementation ACMemoryCache

- (nullable instancetype)initWithName:(NSString *)name {
    return [self initWithName:name type:ACMStorageTypeLFUCache];
}

- (instancetype)initWithName:(NSString *)name type:(ACMStorageType)type {
    self = [super init];
    if (self) {
        _storageType = type;
        _name = name;
        switch (type) {
            case ACMStorageTypeSystemCache: {
                _cache = [[ACNSCache alloc] init];
                _cache.name = _name;
                __weak typeof(self) _self = self;
                _cache.didReceiveMemoryWarningBlock = ^(ACNSCache *cache) {
                    __strong typeof(_self) self = _self;
                    !self.didReceiveMemoryWarningBlock?:self.didReceiveMemoryWarningBlock(self);
                };
                _cache.didEnterBackgroundBlock = ^(ACNSCache *cache) {
                    __strong typeof(_self) self = _self;
                    !self.didEnterBackgroundBlock?:self.didEnterBackgroundBlock(self);
                };
            }
                break;
            case ACMStorageTypeLFUCache: {
                _lfuCache = [[ACLFUCache alloc] init];
                __weak typeof(self) _self = self;
                _lfuCache.didReceiveMemoryWarningBlock = ^(ACLFUCache *cache) {
                    __strong typeof(_self) self = _self;
                    !self.didReceiveMemoryWarningBlock?:self.didReceiveMemoryWarningBlock(self);
                };
                _lfuCache.didEnterBackgroundBlock = ^(ACLFUCache *cache) {
                    __strong typeof(_self) self = _self;
                    !self.didEnterBackgroundBlock?:self.didEnterBackgroundBlock(self);
                };
            }
                break;
        }
    }
    return self;
}

- (nullable id)objectForKey:(nonnull id)key {
    id obj;
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            obj = [_cache objectForKey:key];
        }
            break;
        case ACMStorageTypeLFUCache: {
            obj = [_lfuCache objectForKey:key];
        }
            break;
    }
    return obj;
}

- (void)setObject:(nullable id)object forKey:(nonnull id)key {
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            [_cache setObject:object forKey:key];
        }
            break;
        case ACMStorageTypeLFUCache: {
            [_lfuCache setObject:object forKey:key];
        }
            break;
    }
}

- (void)setObject:(nullable id)object forKey:(nonnull id)key cost:(NSUInteger)cost {
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            [_cache setObject:object forKey:key cost:cost];
        }
            break;
        case ACMStorageTypeLFUCache: {
            [_lfuCache setObject:object forKey:key cost:cost];
        }
            break;
    }
}

- (void)removeObjectForKey:(nonnull id)key {
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            [_cache removeObjectForKey:key];
        }
            break;
        case ACMStorageTypeLFUCache: {
            [_lfuCache removeObjectForKey:key];
            break;
        }
    }
}

- (void)removeAllObjects {
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            [_cache removeAllObjects];
        }
            break;
        case ACMStorageTypeLFUCache: {
            [_lfuCache removeAllObjects];
            break;
        }
    }
}

- (void)setCountLimit:(NSUInteger)countLimit {
    _countLimit = countLimit;
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            if (_cache && _cache.countLimit != countLimit) {
                _cache.countLimit = countLimit;
            }
        }
            break;
        case ACMStorageTypeLFUCache: {
            if (_lfuCache && _lfuCache.countLimit != countLimit) {
                _lfuCache.countLimit = countLimit;
                [_lfuCache trimToCount:countLimit];
            }
            break;
        }
    }
}

- (void)setCostLimit:(NSUInteger)costLimit {
    _costLimit = costLimit;
    switch (_storageType) {
        case ACMStorageTypeSystemCache: {
            if (_cache && _cache.totalCostLimit != costLimit) {
                _cache.totalCostLimit = costLimit;
            }
        }
            break;
        case ACMStorageTypeLFUCache: {
            if (_lfuCache && _lfuCache.costLimit != costLimit) {
                _lfuCache.costLimit = costLimit;
                [_lfuCache trimToCost:costLimit];
            }
            break;
        }
    }
}

- (BOOL)containsObjectForKey:(id)key {
    return [_lfuCache containsObjectForKey:key];
}

- (NSArray *)allkeys {
    return [_lfuCache allkeys];
}

- (NSArray *)allValues {
    return [_lfuCache allValues];
}

- (NSUInteger)totalCount {
    return _lfuCache.totalCount;
}

- (NSUInteger)totalCost {
    return _lfuCache.totalCost;
}


- (void)dealloc {
    NSLog(@"%s",__func__);
}

@end
